//
// Created by hjie on 23-9-17.
//

#include "stun_server.h"
#include "message_process.h"
#include "./../stun_message.h"

StunServer::StunServer(LoopEvent *loop_event)
{
    m_loop_event = loop_event;
    m_udp_server = nullptr;
}

StunServer::~StunServer()
{
    if (m_udp_server)
    {
        delete m_udp_server;
        m_udp_server = nullptr;
    }
}

int StunServer::Listen(int port)
{
    m_process_ptr = std::make_shared<MessageProcess>(this);
    m_listen_port = port;
    m_udp_server = new UdpServer(m_loop_event);
    m_udp_server->SetUdpMessage(std::bind(&StunServer::OnMessage, this, std::placeholders::_1));
    m_udp_server->Listen(m_listen_port);

    return true;
}

void StunServer::OnMessage(UdpPacket *packet)
{
    UdpBufferPacket buffer_packet{};
    DataBuffer data(m_udp_server->GetSocketFd());

    buffer_packet.buffer = &data;
    buffer_packet.buffer->PushDataBuffer(packet->data, packet->length);

    buffer_packet.sai = (struct sockaddr*)&packet->sai;
    buffer_packet.sai_len = sizeof(packet->sai);
    do
    {
        int use_length = 0;
        StunMessage message;
        ParseStatus status = message.ParseStunMessage(&buffer_packet, use_length);
        if (status == EmParseFinishStatus)
        {
            buffer_packet.buffer->RemoveData(use_length);
            ProcessStunMessage(buffer_packet, message);
            break;
        }
        else if (status == EmUnknownStatus)
        {
            // drop packet
            buffer_packet.buffer->RemoveData(buffer_packet.buffer->Length());
            break;
        }

    }while (true);
}

void StunServer::ProcessStunMessage(UdpBufferPacket &packet, StunMessage &message)
{
    WriteBuffer buffer;
    switch (message.GetMsgType())
    {
        case EmBindRequest:
        {
            m_process_ptr->ProcessRequest(message, buffer);
            break;
        }
        case EmBindResponse:
        {
            break;
        }
        default:
            break;
    }
    if (buffer.Length() > 0)
    {
        m_udp_server->SendMsg(packet, buffer.Data(), buffer.Length());
    }
}

